/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package hirt;

import java.util.LinkedList;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JButton;
import java.awt.Point;
import java.nio.ByteBuffer;
import java.util.Vector;
/**
 *
 * @author zamille
 */
public class HirtClient extends Client
{
    /**The local player*/
    private Player localPlayer;
    /**The session the local player is playing*/
    private Session localSession;
    /** The user interface that the player is using*/
    private MainFrame GUI;
    /**Thread that automatically increments the time when it needs to*/
    Thread timeCounter;
    /** Should time be incrementing now?*/
    boolean countTime;
    /**debugMode add several features that would hert players and help developers*/
    boolean debugMode;

    /**
     *
     */
    public HirtClient() //TODO add way to send stuff back to GUI
    {
        super();
        localPlayer= new Player();
        localSession = new Session(-1);
        GUI = null;

        setDebugMode( false );
    }

    /**
     *
     * @param GUI
     */
    public HirtClient( MainFrame GUI )
    {
        this();

        localPlayer.setName( "hirtPlayer" );
        this.GUI = GUI;

        try
        {
            //localPlayer.joinSession( localSession );
            //localSession.addPlayer( localPlayer );
        } catch (Exception ex)
        {
            //Logger.getLogger(HirtClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        setupClock();
    }

    /**
     *
     * @param GUI
     * @param localPlayer
     * @param localSession
     */
    public HirtClient ( MainFrame GUI, Player localPlayer, Session localSession)
    {
        this( GUI );
        
        this.localPlayer = localPlayer;
        this.localSession = localSession;
        //state = localSession.getState();
        //setupClock();
    }

    /**
     * Initiates timeCounter with the code need to keep the clock up to date
     */
    private void setupClock()
    {
        //System.out.println("SETUP CLOCK");
        timeCounter = new Thread() {
            public void run() {
                try {
                    while (true)
                    {
                        Thread.sleep(1000);
                        if (countTime)
                        {
                            Scenario currentScenario = localSession.getCurrentScenario();
                            currentScenario.setCurrentTime(currentScenario.getCurrentTime() + 1);
                            GUI.mainScreenPanel.refreshTime();
                            //System.out.println("REFRESH TIME");
                        }


                        
                    }
                } catch (Exception ex) {
                    System.out.println("CLOCK ERROR:  " + ex.getMessage());
                }
            }
        };
        timeCounter.start();
    }


    /**
     * Initializes a default session
     * @throws Exception
     */
    public void createSession() throws Exception
    {
       localSession = localPlayer.createSession( -1 );
       //state = localSession.getState();
        //Send Session to Server
       //setupClock();
    }

    /**
     * Sends a chat message to the server to be distributed
     * or calls console code if message begins with '/'
     * @param chatMessage
     */
    public void sendChatMessage(String chatMessage)
    {
        if (chatMessage.startsWith("/"))
        {
            consoleCommand(chatMessage.substring(1));
        }
        else
        {
            //String sentText = localPlayer.getName() + ": " + chatMessage;
            CommunicationAction communique = new CommunicationAction(localPlayer, chatMessage);
            Message message = new Message(Message.CHAT_MESSAGE, communique);

            //Send Message to Server
            sendMessage(message);
            //recieveChatMessage(communique);

            GUI.mainScreenPanel.displayDirections( Feedback.SENT_MESSAGE );
        }
    }

    /**
     * Tells the server that the passed car's onFire value equals the passed onFire
     * @param car
     * @param onFire
     */
    public void setOnFire(Automobile car, boolean onFire)
    {
        sendCarCondition(car, onFire, car.moveable,car.damaged, car.lightStatus);
    }

     /**
     * Tells the server that the passed car's movable value equals the passed movable
     * @param car
     * @param movable
     */
    public void setMovable(Automobile car, boolean moveable)
    {
        sendCarCondition(car, car.onFire, moveable,car.damaged, car.lightStatus);
    }

     /**
     * Tells the server that the passed car's damaged value equals the passed damaged
     * @param car
     * @param damaged
     */
    public void setDamage(Automobile car, boolean damaged)
    {
        sendCarCondition(car, car.onFire, car.moveable,damaged, car.lightStatus);
    }

     /**
     * Tells the server that the passed car's light value equals the passed lightStatus
     * @param car
     * @param lightStatus
     */
    public void setLights(Automobile car, int lightStatus)
    {
        sendCarCondition(car, car.onFire, car.moveable,car.damaged, lightStatus);
    }

    /**
     * Tells the server to sets the passed car's various condition values to the passed values
     * @param car
     * @param fire
     * @param moves
     * @param damage
     * @param lights
     */
    public void sendCarCondition(Automobile car, boolean fire, boolean moves, boolean damage, int lights)
    {
        CarConditionAction action = new CarConditionAction(car, fire, moves, damage, lights);
        Message message=  new Message(Message.CAR_CONDITION_MESSAGE, action);
        sendMessage(message);

        GUI.mainScreenPanel.displayDirections( Feedback.CHANGED_CAR_CONDITION );
    }

    /**
     * Sends basic requests on to the server
     * @param sender
     * @param reciever
     * @param requestType
     */
    public void sendRequest(Item sender, Item reciever, byte requestType)
    {
        String sentText = "";
        if (requestType == CommunicationAction.TYPE_REQUESTMOVE)
            sentText = /*localPlayer.getName() + */" requests that " + reciever.toString() + " be moved.";
        else if (requestType == CommunicationAction.TYPE_REQUESTCAR)
            sentText = /*localPlayer.getName() + */": requests an additional " + reciever.type + ".";
        CommunicationAction communique = new CommunicationAction(sender, 0,sentText,reciever,requestType);

        //Send Message to Server
        recieveChatMessage(communique);
    }

    /**
     * Recieves message buf and calls the proper method depending on the message type
     * @param buf
     */
    @Override
    protected void recieveMessage(byte[] buf)
    {
        //int type = packet.;

        ByteBuffer buffer = ByteBuffer.wrap(buf);
        //recreate the message from the passed bytes
        Message received = new Message(buffer, localSession.getCurrentScenario().getItemList());
        System.out.println("Recieved Message Type:  " + received.type);
        byte type = received.type;
        //type is the first part of the message which denotes the type of message
        //CommunicationAction message = (CommunicationAction)received.content;
        //recieved is the data that came with the message
        switch (type)
        {
            case 0: 				//close connection message
                    //GUI.writeChatMessage("Connection closed\n");
                    break;
            case Message.CHAT_MESSAGE: 				//chat message
                recieveChatMessage((CommunicationAction) received.content);
                break;
            case Message.MOVE_MESSAGE:
                recieveMoveMessage((MovementAction) received.content);
                break;
            case Message.CREATE_MESSAGE:
                recieveCreateMessage((CreationAction) received.content);
                break;
            case Message.TRANSFER_MESSAGE:
                recieveTransferMessage((TransferAction) received.content);
                break;
            case Message.PLAYERCHANGE_MESSAGE:
                recievePlayerChangeMessage((PlayerChangeAction) received.content);
                break;
            case Message.LOCALPLAYERCREATE_MESSAGE:
                initalizeLocalPlayer((CreationAction) received.content);
                break;
            case Message.REMOVE_MESSAGE:
                removeItemMessage((RemoveAction) received.content);
                break;
            case Message.REFRESH_TIME_MESSAGE:
                refreshTime(received.content);
                countTime = true;
                break;
            case Message.EDITOR_MODE_MESSAGE:
            case Message.PLAY_MODE_MESSAGE:
            case Message.REVIEW_MODE_MESSAGE:
                handleModeChange(type);
                break;
            case Message.SAVE_SCENARIO_MESSAGE:
                GUI.recieveChat("Scenario Save Successful");
            case Message.SCENARIO_DATA_MESSAGE:
                handleScenarioData((ScenarioDataAction) received.content);
                break;
            case Message.CLEAR_SCENARIO_MESSAGE:
                clearScenario();
                break;
            case Message.LOCALPLAYERASSIGN_MESSAGE:
                localPlayer = (Player)received.content.actor;
                break;
            case Message.CAR_CONDITION_MESSAGE:
                handleCarConditionChange((CarConditionAction)received.content);
                break;
            case Message.SET_LANE_ADJACENCY_MESSAGE:
                setLaneAdjacencies((TransferAction) received.content);
                break;


        default: System.out.println("Unrecognized type: " + type);
        }
        
        byte length = received.length;
        if (length > buffer.limit())
        {
            try {
                buffer = ByteChanger.truncate(buffer, length);
                //recieveMessage(buffer.array());
            } catch (Exception ex) {
                
            }
            
        }

    }

    /**
     * Called when the client recieves a Chat Message from the server
     * it displays the passed message in the GUI chatroom
     * @param communique
     */
    private void recieveChatMessage(CommunicationAction communique)
    {
        String openingMessage = "";
        Player player;
        Item actor = communique.getActor();
        while (true)
        {
            if (actor == null)
            {
                openingMessage = "";
                break;
            }
            if (actor instanceof Player)
            {
                player = (Player) actor;
                openingMessage = player.getName() + ": ";  //displays the message in the form of
                break;                                     //name: message
            }
            else
            {
                if (actor.getOwner() == null)
                {
                    openingMessage = "";
                    break;

                }
                else
                {
                    actor = actor.owner;
                }
            }
        }
        if (communique.getType() != CommunicationAction.TYPE_CHAT)
        {
            GUI.recieveRequest(openingMessage + communique.getMessage());
        }
        else
        {
            GUI.recieveChat(openingMessage + communique.getMessage());
        }
        localSession.addChatMessage(communique);
    }

    /**
     * Called whenever the client recieves a MovementAction
     * @param movement
     */
    public void recieveMoveMessage(MovementAction movement)
    {
        //GUI.gameScenePanel.receiveItemMove(movement);
        GUI.receiveItemMove(movement);
    }

    /**
     * Sends item movements to the server
     * item angle will remain the same
     * @param actor moving
     * @param start point
     * @param end point
     */
    public void moveItem(Item actor, Point start, Point end)
    {
        float angle = 0;
        if (actor instanceof Item2D)
        {
            Item2D tmp = (Item2D) actor;
            angle = tmp.getAngle();
        }
        moveItem(actor,start,end,angle);
    }

    /**
     * Sends item movements to the server
     * @param actor moving
     * @param start point
     * @param end point
     * @param new angle
     */
    public void moveItem(Item actor, Point start, Point end, float angle)
    {
        double time = localSession.getCurrentScenario().getCurrentTime();
        MovementAction movement = new MovementAction(actor,time,0,end,start, angle);
        Message message = new Message(Message.MOVE_MESSAGE, movement);
        //TODO send movement to server
        sendMessage(message);
    }

    /**
     * Sends transfer information to the server
     * @param actor
     * @param moved
     * @param reciever
     */
    public void sendTransfer(Item actor, Item moved, Item reciever)
    {
        TransferAction transfer = new TransferAction(actor, moved, reciever);
        Message message = new Message(Message.TRANSFER_MESSAGE, transfer);

        sendMessage(message);
    }

    /**
     * Sends transfer information to the server
     * @param moved
     * @param reciever
     */
    public void sendTransfer(Item moved, Item reciever)
    {
        sendTransfer(null,moved,reciever);
    }

    /**
     * Sends request to the server to remove the passed item
     * @param removed item
     */
    public void sendRemove(Item removed)
    {
        RemoveAction remove = new RemoveAction(removed);
        Message message = new Message(Message.REMOVE_MESSAGE, remove);
        
        sendMessage(message);
    }

    /**
     * Sends request to the server to remove amount items of type type from owner inventory
     * @param owner of itmes
     * @param type of item to remove
     * @param amount to remove
     */
    public void sendRemove(Item owner, String type, int amount)
    {
        RemoveAction remove = new RemoveAction(owner,type,amount);
        Message message = new Message(Message.REMOVE_MESSAGE, remove);

        sendMessage(message);
    }


    /**
     * Send request to switch to editor mode to server
     */
    public void sendEditorModeRequest()
    {
        Message message = new Message(Message.EDITOR_MODE_MESSAGE);
        sendMessage(message);

        GUI.mainScreenPanel.displayDirections( Feedback.EDITOR_MODE );
    }

    /**
     * Send request to switch to play mode to server
     */
    public void sendPlayModeRequest()
    {
        Message message = new Message(Message.PLAY_MODE_MESSAGE);
        sendMessage(message);

        GUI.mainScreenPanel.displayDirections( Feedback.PLAY_MODE );
    }

    // TODO Tim2Zack - Insert a container paramater PLEASE
    // TODO Andrew2Zack - I bet you ownerID is being used for owner & container
    /**
     * Send Requests to the server to make an item of passed type
     * @param requestedType
     * @param Class of created item
     * @param ownerID of created item
     * @param x position of created item
     * @param y position of created item
     */
    public void sendCreateRequest(String requestedType, String Class, int ownerID, int x, int y)
    {
        RequestCreateAction create = new RequestCreateAction(requestedType, Class, ownerID, x, y);
        Message message = new Message(Message.REQUEST_CREATE_MESSAGE, create);
        sendMessage(message);
    }

    /**
     * Send Requests to the server to make several item of passed type
     * @param requestedType
     * @param Class of created item
     * @param ownerID of created item
     * @param x position of created item
     * @param y position of created item
     * @param amount of item of create
     */
    public void sendCreateRequest(String requestedType, String Class, int ownerID, int x, int y, int amount)
    {
        RequestCreateAction create = new RequestCreateAction(requestedType, Class, ownerID, x, y, amount);
        Message message = new Message(Message.REQUEST_CREATE_MESSAGE, create);
        sendMessage(message);
    }

    /**
     * Send Requests to the server to make an item of passed type
     * @param requestedType
     * @param Class of created item
     * @param ownerID of created item
     */
    public void sendCreateRequest(String requestedType, String Class, int ownerID)
    {

        sendCreateRequest(requestedType, Class, ownerID, 0, GUI.gameScenePanel.HEIGHT);
    }

    /**
     * Sends request to the server to change the local player name to newName
     * @param newName
     */
    public void changeName(String newName)
    {
        PlayerChangeAction action = new PlayerChangeAction(localPlayer, newName);
        Message message = new Message(Message.PLAYERCHANGE_MESSAGE, action);
        sendMessage(message);
    }

    /**
     * Tells the server to move item Actor to point End
     * @param actor
     * @param end
     */
    public void placeItem(Item actor, Point end)
    {
        moveItem(actor, null, end);
    }

    public void refreshRole()
    {
        //Role myRole = new Role(localPlayer.currentRole);  // TODO: Figure this shit out, please.
        // send Role data to Server to Refresh it
    }

    /**
     * adds newRole to localPlayer
     * @param newRole
     */
    public void addRole(int newRole)
    {
        changeRole(newRole);

        GUI.mainScreenPanel.displayDirections( Feedback.ADDED_ROLE );
    }

    /**
     * if localPlayer contains newRole: this removes it
     * if localPlayer doesn't:it adds newRole to the localPlayer
     * @param newRole
     */
    private void changeRole(int newRole)
    {
        if (Role.validId(newRole))
        {
            PlayerChangeAction newRoleAction = new PlayerChangeAction(localPlayer, newRole);
            Message message = new Message(Message.PLAYERCHANGE_MESSAGE, newRoleAction);
            sendMessage(message);
            //System.out.println("LocalPlayer has changed a Role");
            
        }
    }

    /**
     * Called when client recieves a PlayerChangeAction
     * and needs to add a role to the localplayer
     * @param action
     */
    private void recieveAddRole(PlayerChangeAction action)
    {
        Player player = (Player)action.getActor();
        changeRole (player, action.newRole);
    }

    /**
     * Called when client recieves a PlayerChangeAction
     * and needs to remove a role from the localplayer
     * @param action
     */
    private void recieveRemoveRole(PlayerChangeAction action)
    {
        Player player = (Player)action.getActor();
        changeRole (player, action.newRole);
    }

    /**
     * if Player contains Role: this removes it
     * if Player doesn't:it adds Role to the Player
     * @param player
     * @param Role
     */
    private void changeRole(Player player, Role role)
    {
        try
        {
            boolean hasRole = player.containsRole(role.getId());
            Vector<Item> items = localSession.currentScenario.getItemList();
            //if (player.containsRole(role.getId()))
            //{
                if (hasRole)
                    player.removeRole(role.getId());
                else
                {
                    Player playerWithRole = localSession.getPlayerByRole(role.getId());
                    if (playerWithRole != null)
                    {
                        playerWithRole.removeRole(role.getId());
                        LinkedList<Item> carList = playerWithRole.itemList;
                        Item item;
                        Automobile car;
                        for(int i = 0; i < carList.size(); i++)
                        {
                            item = carList.get(i);
                            if (item instanceof Automobile)
                            {
                                car = (Automobile)item;
                                if (car.roleId == role.getId())
                                    playerWithRole.removeCar(car);
                            }
                        }
                    }
                    player.addRole(role.getId());
                }
                for (int i = 0; i< items.size(); i++)
                {
                    Item item = items.get(i);
                    if ((item instanceof Automobile))
                    {
                        Automobile car = (Automobile)item;
                        if (car.getRoleId() == role.getId())
                        {
                           if (hasRole)
                               player.removeCar(car);
                           else
                               player.addCar(car);

                        }
                    }
                }
           /* }
            else
            {
                player.addRole(role.getId());
                for (int i = 0; i< items.size(); i++)
                {
                    Item item = items.get(i);
                    if (item.owner == null && (item instanceof Automobile))
                    {
                        Automobile car = (Automobile)item;
                        if (car.getRoleId() == role.getId())
                        {
                            player.addCar(car);
                        }
                    }
                }
            }*/

        }
        catch (Exception ex)
        {
            GUI.recieveChat("CHANGE ROLE: ERROR: Couldn't add Role:  " + ex.getMessage());
        }
    }

    /**
     * used to remove oldRole from the localPlayer
     * @param oldRole
     */
    public void removeRole(int oldRole)
    {
        if (Role.validId(oldRole))
        {
            /*try
            {
                localPlayer.removeRole(oldRole);
            }
            catch (Exception ex)
            {
                GUI.recieveChat("ERROR: Couldn't remove Role:  " + ex.getMessage());
            }*/
            changeRole(oldRole);

            GUI.mainScreenPanel.displayDirections( Feedback.REMOVED_ROLE );
        }
    }

    public Session getSession()
    {
        return localSession;
    }

    public Player getLocalPlayer()
    {
        return localPlayer;
    }

    public MainFrame getGUI()
    {
        return GUI;
    }

    public void setGUI(MainFrame GUI)
    {
        this.GUI = GUI;
    }

    /*public int checkStates()
    {
        int state = localSession.getState();
        switch(state)
        {
            case Session.STATE_INITIALIZE: state = handleInitializeState(); break;
            case Session.STATE_WAITING: state = handleWaitingState(); break;
            case Session.STATE_PLAYING: state = handlePlayingState(); break;
            case Session.STATE_REVIEW: state = handleReviewState(); break;
            case Session.STATE_DESTROY: state = handleDestroyState(); break;
            default: GUI.recieveChat("Session got all messed up");
        }
        return state;
    }*/

    private int handleInitializeState()
    {
        return localSession.getState();
    }

    private int handleWaitingState()
    {
        //TODO rewrite using player roles instead of buttons
        if (localSession.currentScenario != null)
        {
            boolean filled = true;
            JButton[] responders = GUI.mainScreenPanel.responderButton;

            for (int i = 0; i < responders.length; i++)
            {
                if (responders[i].getText().equals(""))
                    filled = false;
            }

            GUI.enableGameStart(filled);
        }
        return localSession.getState();
    }

    /*private int handlePlayingState()
    {
        int subState = localSession.getSubState();
        switch (subState)
        {
            case Session.SUBSTATE_PLACECAR:
                int parking = localPlayer.getCurrentCar().getStatus();
                if (parking == Automobile.STATE_PARKED)
                    localSession.setSubState(Session.SUBSTATE_NULL);
                break;
            case Session.SUBSTATE_PLACEITEM:
               Item mouse = GUI.mouseDraggedItemReference;
               Item placingItem = mouse.getItem(0);
               if (placingItem == null || placingItem.getStatus() == Item2D.STATE_PLACED)
               {
                   localSession.setSubState(Session.SUBSTATE_NULL);
               }
               else if (!localPlayer.getCurrentCar().itemList.contains(placingItem))
               {
                   placingItem.setStatus(Item2D.STATE_PLACED);
                   localSession.setSubState(Session.SUBSTATE_NULL);
               }
               break;
        }

        Scenario scenario = localSession.getCurrentScenario();

        if (scenario.getObjectives().isEmpty())
        {
            boolean complete = true;
            LinkedList<Item> itemList = localPlayer.getItemList();
            for (int i = 0; i < itemList.size(); i++)
            {
                if (!(itemList.get(i).getStatus() == Automobile.STATE_LEAVING))
                    complete = false;
            }
            if (complete)
                localSession.nextState();
        }

        return localSession.getState();
    }*/

    private int handleReviewState()
    {
        localSession.nextState();
        return localSession.getState();
    }

    private int handleDestroyState()
    {
        return localSession.getState();
    }

    /**
     * Gets the player playing the passed role
     * @param roleId
     * @return player playeing passed role
     */
    public Player getPlayerByRole( int roleId )
        {
            return localSession.getPlayerByRole(roleId);
        }

    /**
     * returns the ID of the passed item if it is an Automobile
     * Otherwise it return -1
     * @param item
     * @return
     */
    public int isAutomobile(Item item)
    {
        if (item instanceof Automobile)
        {
            Automobile car = (Automobile)item;
            return car.getRoleId();
        }
        return -1;
    }

    /**
     * Called when the client receives a Create Message
     * It uses the information to create the new item and add to the scenario
     * at it's proper posistion
     * @param creationAction
     */
    private void recieveCreateMessage( CreationAction creationAction )
    {
        Item createdItem = creationAction.actor;
        Session session = getSession();

        Scenario currentScenario = session.getCurrentScenario();
        if( createdItem instanceof Player )
        {
            try
            {
                session.addPlayer( ( Player )createdItem );  //add a player to the playerlist
            }
            catch( Exception ex )
            {
                System.out.println( "HirtClient.recieveCreateMessage():  ERROR adding player:  " + ex.getMessage());
            }
            GUI.mainScreenPanel.refreshResponders();
        }
        else if( currentScenario != null )
        {
            currentScenario.addItem( createdItem , createdItem.id );
            if (createdItem instanceof Automobile)
            {
                Automobile car = (Automobile) createdItem;          //when adding cars
                Player player = getPlayerByRole(car.getRoleId());   //it needs to be added
                if (player!=null)                               //to the item list of the player
                    player.addCar(car);                        //controlling that car's role

            }
        }

        GUI.receiveItemCreation( creationAction );
        GUI.gameScenePanel.initializeScene();
        if (creationAction.actor instanceof Automobile && localSession.mode == Session.MODE_PLAY && creationAction.firstTime)
            GUI.recieveChat(creationAction.actor.toString() + " is on its way");
    }

    /**
     * Called when the client receives a Transfer Message
     * @param transferAction
     */
    private void recieveTransferMessage(TransferAction transferAction) {
        GUI.receiveItemTransfer(transferAction);
    }

    /**
     * Called when the client recieves a Player Change Message
     * It either changes the players name
     * Gives the player a role
     * Or Removes a role from the player
     * @param playerChangeAction
     */
    private void recievePlayerChangeMessage(PlayerChangeAction playerChangeAction) {
        switch (playerChangeAction.type)
        {
            case PlayerChangeAction.CHANGE_NAME:
                GUI.recieveNameChange(playerChangeAction);

                break;
            case PlayerChangeAction.ADD_ROLE:
                recieveAddRole(playerChangeAction);
                break;
            case PlayerChangeAction.REMOVE_ROLE:
                recieveRemoveRole(playerChangeAction);
                break;
        }
        GUI.mainScreenPanel.refreshResponders();
        GUI.mainScreenPanel.refreshVehicle();
        GUI.mainScreenPanel.refreshItems();
        //GUI.receiveItemTransfer(transferAction);
    }

    /**
     * Called when the server passes all the inforamtion the client needs to create
     * the local player
     * @param creationAction
     */
    private void initalizeLocalPlayer(CreationAction creationAction) {
        localPlayer = (Player)creationAction.getActor();
        try {
            localSession.addPlayer(localPlayer);
        } catch (Exception ex) {
            System.out.println("ERROR JOINGING SESSION:  " + ex.getMessage());
        }
        GUI.gameScenePanel.initializeScene();
        GUI.gameScenePanel.drawBackground(true);
    }

    /**
     * Called when the client receives a remove message
     * @param removeAction
     */
    private void removeItemMessage(RemoveAction removeAction) {
        Item actor = removeAction.getActor();
        if (actor instanceof Player)
        {

            Player plays = (Player)actor;
            try {
                localSession.removePlayer(plays);
            } catch (Exception ex) {
                System.out.println("removeItemMessage: Can't remove player from session: " + ex.getMessage());
            }
            GUI.recieveChat(plays.getName() + " just left the game");
            GUI.mainScreenPanel.refreshResponders();
        }
        else
        {
            localSession.removeItem(actor);
            
        }
        GUI.mainScreenPanel.refreshVehicle();
        GUI.mainScreenPanel.refreshItems();
    }


    /**
     * Used to have easy way to call a function
     * mostly used for debug purposes
     * @param command
     */
    private void consoleCommand(String command)
    { if (command.startsWith("name "))
        {
            changeName(command.substring(5));
        }
        else
        if( command.startsWith( "listroles" ) )
        {
            consoleCommandListRoles();
        }
        else
        if( command.startsWith( "listautos" ) )
        {
            consoleCommandListAutos();
        }
        else
        if( command.startsWith( "currentcar" ) )
        {
            consoleCommandCurrentCar();
        }
        else
        if( command.startsWith( "inventory" ) )
        {
            consoleCommandListInventory();
        }
        else
        if( command.startsWith( "worlditems" ) )
        {
            consoleCommandListWorldItems();
        }
        else
        if( command.startsWith( "drawbackground" ) )
        {
            consoleCommandDrawBackground();
        }
        else
        if( command.startsWith( "printitems" ) )
        {
            consolePrintItems();
        }
        else
        if( command.startsWith( "printscenarios" ) )
        {
            consolePrintScenarios();
        }
        else
        if ( command.startsWith( "scenario " ) )
        {
            sendLoadScenario(command.substring(9));
        }
        else
        if ( command.startsWith( "printlocalplayer" ) )
        {
            System.out.println(localPlayer.toSaveString());
        }
        else
        if ( command.startsWith( "listplayers" ) )
        {
            consoleCommandListPlayers();
        }
        else
        if ( command.startsWith( "debug" ) )
        {
            consoleCommandToggleDebugMode();
        }
    }

    /**
     * Lists all the roles the local player has in the GUI
     */
    private void consoleCommandListRoles()
    {
        int index;

        if( localSession == null )
        {
            System.out.println( "consoleCommandListRoles(): no local session." );
            return;
        }

        if( localPlayer == null )
        {
            System.out.println( "consoleCommandListRoles(): no local player." );
            return;
        }

        Vector<Role> roleList = localPlayer.getRoles();

        if( roleList.size() == 0 )
        {
            GUI.recieveChat( "*Local player has no roles." );
        }
        else
        {
            GUI.recieveChat( "*Local player has roles:" );

            for( index = 0; index < roleList.size(); index++ )
            {
                GUI.recieveChat( Role.getName( roleList.get( index ).getId() ) );
            }
        }
    }

    /**
     * Lists all the cars the local player has in the GUI
     */
    private void consoleCommandListAutos()
    {
        int index;

        if( localSession == null )
        {
            System.out.println( "consoleCommandListAutos(): no local session." );
            return;
        }

        if( localPlayer == null )
        {
            System.out.println( "consoleCommandListAutos(): no local player." );
            return;
        }

        Vector<Automobile> carList = localPlayer.getCarList();

        if( carList.size() == 0 )
        {
            GUI.recieveChat( "*Local player has no automobiles." );
        }
        else
        {
            GUI.recieveChat( "*Local player has automobile:" );

            for( index = 0; index < carList.size(); index++ )
            {
                Automobile tempAutomobile = carList.get( index );

                GUI.recieveChat( tempAutomobile.getType() + " #" + tempAutomobile.getInstance() );
            }
        }
    }

    /**
     * Lists the current car in the GUI
     */
    private void consoleCommandCurrentCar()
    {
        if( localSession == null )
        {
            System.out.println( "consoleCommandListAutos(): no local session." );
            return;
        }

        if( localPlayer == null )
        {
            System.out.println( "consoleCommandListAutos(): no local player." );
            return;
        }

        Automobile currentCar = localPlayer.getCurrentCar();

        if( currentCar == null )
        {
            GUI.recieveChat( "*Local player has no current car." );
        }
        else
        {
            GUI.recieveChat( "*Local player's current car:" );
            GUI.recieveChat( currentCar.getType() + " #" + currentCar.getInstance() );
        }
    }

    /**
     * Lists all the the current car has in the GUI
     */
    private void consoleCommandListInventory()
    {
        if( localSession == null )
        {
            System.out.println( "consoleCommandListInventory(): no local session." );
            return;
        }

        if( localPlayer == null )
        {
            System.out.println( "consoleCommandListInventory(): no local player." );
            return;
        }

        Automobile currentCar = localPlayer.getCurrentCar();

        if( currentCar == null )
        {
            GUI.recieveChat( "*Local player has no current car." );
        }
        else
        {
            int index;

            int size = currentCar.getItemList().size();

            if( size == 0 )
            {
                GUI.recieveChat( currentCar.getType() + " #" + currentCar.getInstance() +
                    " has no items." );
            }
            else
            {
                GUI.recieveChat( currentCar.getType() + " #" + currentCar.getInstance() +
                    " has items:" );

                for( index = 0; index < currentCar.getItemList().size(); index++ )
                {
                    Item item = currentCar.getItemList().get( index );

                    GUI.recieveChat( item.getType() );
                }
            }
        }
    }

    /**
     * Lists all the the world has in the GUI
     */
    private void consoleCommandListWorldItems()
    {
        if( localSession == null )
        {
            System.out.println( "consoleCommandListWorldItems(): no local session." );
            return;
        }

        Scenario currentScenario = localSession.getCurrentScenario();

        if( currentScenario == null )
        {
            System.out.println( "consoleCommandListWorldItems(): no current scenario." );
            return;
        }

        Item2D world = localSession.getCurrentScenario().getWorld();

        if( world == null )
        {
            System.out.println( "consoleCommandListWorldItems(): world is null." );
            return;
        }

        // List all the items in the world's itemList.
        GUI.recieveChat( "*Items in the visible world:" );

        LinkedList<Item> itemList = world.getItemList();

        int index;
        for( index = 0; index < itemList.size(); index++ )
        {
            Item2D item2d = ( Item2D )itemList.get( index );

            if( item2d instanceof Lane )
            {
                Lane lane = ( Lane )item2d;

                GUI.recieveChat( "Lane (" + lane.getType() + ")" + " #" + lane.getId() );
            }
            else
            if( item2d instanceof Automobile )
            {
                Automobile automobile = ( Automobile )item2d;

                GUI.recieveChat( automobile.getType() + " #" + automobile.getId() +
                        ", instance #" + automobile.getInstance() );
            }
            else
            {
                GUI.recieveChat( item2d.getType() + " #" + item2d.getId() );
            }
        }
    }

    /**
     * Lists all the players in the GUI
     */
    private void consoleCommandListPlayers()
    {
        Vector<Player> playerList = getSession().getPlayerList();

        GUI.recieveChat( "consoleCommandListPlayers():" );
        
        int index;
        for( index = 0; index < playerList.size(); index++ )
        {
            Player player = playerList.get( index );

            GUI.recieveChat( player.getId() + ":" + player.getName() );
        }
    }

    /**
     * Redraws the background
     */
    private void consoleCommandDrawBackground()
    {
        GUI.recieveChat( "*Draw background." );
        GUI.gameScenePanel.drawBackground( true );
    }

    /**
     * Prints out every item in the master item list
     */
    private void consolePrintItems()
    {
        Vector<Item> items = localSession.currentScenario.itemList;
        String text;
        Item item;
        for (int i = 0; i < items.size();i++)
        {

            item = items.get(i);
            text = item.type + "\tItem: " + item.getId();
            //System.out.print(item.type + "\tItem: " + item.getId());
            if (item.owner != null)
                text += "\tis owned by " + item.owner.getId();

            if (item.container != null)
                text+="\tis contained by " + item.container.getId();
            if (item.itemList.size()>0)
            {
                text+="\tcontains: ";
                for (int j = 0; j < item.itemList.size(); j++)
                {
                    text+=item.itemList.get(j).getId() + ",";
                }
            }
            System.out.println(text);
            //text = item.toString();
            //System.out.println(item.toString());
            //System.out.println(text);
            //text = item.toSaveString();
           // System.out.println(item.toSaveString());
        }
    }

    /**
     * Used to change Debug mode
     */
    public void consoleCommandToggleDebugMode()
    {
        setDebugMode( !getDebugMode() );

        if( getDebugMode() )
        {
            GUI.recieveChat( "Debug Mode: On" );
        }
        else
        {
            GUI.recieveChat( "Debug Mode: Off" );
        }
    }

    /**
     * Asks the server to start a replay
     */
    public void callReplay() {
        System.out.println("Sending replay message");
        Message message = new Message(Message.REVIEW_MODE_MESSAGE);
        sendMessage(message);
    }

    /**
     * refreshes the current time
     * @param content
     */
    private void refreshTime(Action content) {
        try {
            localSession.currentScenario.setCurrentTime(content.startTime);
            GUI.mainScreenPanel.refreshTime();
        } catch (Exception ex) {
            System.out.println("ERROR refreshing current time");
        }
    }

    /**
     * Changes mode to the passed type
     * @param new Mode, Possible Values are the static mode  variables in Session
     */
    private void handleModeChange(byte type) {
        int newMode = 0;
        if (type == Message.REVIEW_MODE_MESSAGE)
        {
            newMode = Session.MODE_REVIEW;
            countTime = true;

        }
        else if (type == Message.EDITOR_MODE_MESSAGE)
        {
            newMode = Session.MODE_EDITOR;
            countTime = false;
        }
        else if (type == Message.PLAY_MODE_MESSAGE)
        {
            newMode = Session.MODE_PLAY;
            countTime = true;
        }
        localSession.setMode(newMode);
        //GUI.mainScreenPanel.updateRoles();
        GUI.mainScreenPanel.refreshResponders();

    }

    /**
     * Called when client receives a ScenarioDataMessage
     * it takes scenario name from the message and adds it
     * to the list of possible scenarios the user sees
     * @param data
     */
    private void handleScenarioData(ScenarioDataAction data) {
        Scenario newScenario = new Scenario();
        newScenario.setName(data.getName());
        if (!localSession.containsScenario(newScenario))
        {
            try {
                localSession.addScenario(newScenario);
            } catch (Exception ex) {
                Logger.getLogger(HirtClient.class.getName()).log(Level.SEVERE, null, ex);
            }
            GUI.mainScreenPanel.refreshScenario();
        }

    }

    /**
     * Clears everything in the scenario in order to start from a fresh plate
     */
    private void clearScenario() {
        localSession.currentScenario.clearScenario();
        localSession.playerList.clear();
        GUI.gameScenePanel.initializeScene();
        GUI.mainScreenPanel.refreshResponders();
    }

    /**
     * Prints out all the scenarios in the scenario list
     */
    private void consolePrintScenarios() {
        Vector<Scenario> list = localSession.getScenarioList();
        System.out.println("SCENARIOS:");
        for (int i = 0; i < list.size(); i++)
            System.out.println(list.get(i).getName());
    }

    /**
     * Sends a request to the server to load the passed scenario
     * @param scenario
     */
    public void sendLoadScenario(String scenario)
    {
        ScenarioDataAction action = new ScenarioDataAction(scenario);
        Message message = new Message(Message.LOAD_SCENARIO_MESSAGE, action);
        sendMessage(message);

        GUI.mainScreenPanel.displayDirections(Feedback.SCENARIO_LOADED);
    }

    /**
     * Sends a request to the server to save the current scenario under the passed name
     * @param fileName
     */
    public void sendSaveScenario(String fileName)
    {
        sendSaveScenario(fileName,"");
    }

    /**
     * Sends a request to the server to save the current scenario under the passed name
     * with the passed description
     * @param fileName
     * @param description
     */
    public void sendSaveScenario(String fileName,String description)
    {
        ScenarioDataAction action = new ScenarioDataAction(fileName, description);
        Message message = new Message(Message.SAVE_SCENARIO_MESSAGE, action);
        sendMessage(message);

        GUI.mainScreenPanel.displayDirections(Feedback.SCENARIO_SAVED);
    }

    /**
     * Called when the client receives a CarConditionMessage
     * Changes the car in the message to the settings speicified in the message
     * @param action
     */
    private void handleCarConditionChange(CarConditionAction action) {
        Automobile car = (Automobile) action.actor;
        car.setFire(action.onFire);
        car.setDamage(action.damaged);
        car.setMoveable(action.movable);
        car.setLightStatus(action.lightSetting);
        GUI.mainScreenPanel.refreshVehicle();

        GUI.mainScreenPanel.displayDirections(Feedback.CHANGED_CAR_CONDITION);
    }

    /**
     * Called when the client receives a Lane Adjacency Message
     * sets the 2 lanes to left and right of each other
     * @param action
     */
    private void setLaneAdjacencies(TransferAction action) {
        Lane left = (Lane) action.reciever;
        Lane right = (Lane) action.moved;
        left.setRight(right);
        right.setLeft(left);
    }

    /**
     * Sends lane adjacency information to the server
     * @param left
     * @param right
     */
    public void sendLaneAdjacencies(Lane left, Lane right)
    {
        TransferAction action = new TransferAction(right, left);
        Message message = new Message(Message.SET_LANE_ADJACENCY_MESSAGE, action);
        sendMessage(message);
        
    }

    public void setDebugMode( boolean set )
    {
        debugMode = set;
    }

    public boolean getDebugMode()
    {
        return( debugMode );
    }

}
